home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / benchmarks / itc / cc1.spur / aux-output.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-08-30  |  9.1 KB  |  313 lines

  1. /* Subroutines for insn-output.c for SPUR.  Adapted from routines for
  2.    the Motorola 68000 family.
  3.    Copyright (C) 1988 Free Software Foundation, Inc.
  4.  
  5. This file is part of GNU CC.
  6.  
  7. GNU CC is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY.  No author or distributor
  9. accepts responsibility to anyone for the consequences of using it
  10. or for whether it serves any particular purpose or works at all,
  11. unless he says so in writing.  Refer to the GNU CC General Public
  12. License for full details.
  13.  
  14. Everyone is granted permission to copy, modify and redistribute
  15. GNU CC, but only under the conditions described in the
  16. GNU CC General Public License.   A copy of this license is
  17. supposed to have been given to you along with GNU CC so you
  18. can know your rights and responsibilities.  It should be in a
  19. file named COPYING.  Among other things, the copyright notice
  20. and this notice must be preserved on all copies.  */
  21.  
  22. static rtx find_addr_reg ();
  23.  
  24. char *
  25. output_compare (operands, opcode, exchange_opcode, 
  26.         neg_opcode, neg_exchange_opcode)
  27.      rtx *operands;
  28.      char *opcode;
  29.      char *exchange_opcode;
  30.      char *neg_opcode;
  31.      char *neg_exchange_opcode;
  32. {
  33.   static char buf[100];
  34.   operands[2] = operands[0];
  35.   if (GET_CODE (cc_prev_status.value1) == CONST_INT)
  36.     {
  37.       operands[1] = cc_prev_status.value1;
  38.       operands[0] = cc_prev_status.value2;
  39.       opcode = exchange_opcode, neg_opcode = neg_exchange_opcode;
  40.     }
  41.   else
  42.     {
  43.       operands[0] = cc_prev_status.value1;
  44.       operands[1] = cc_prev_status.value2;
  45.     }
  46.   if (TARGET_LONG_JUMPS)
  47.       sprintf (buf,
  48.            "cmp_br_delayed %s,%%0,%%1,1f\n\tnop\n\tjump %%l2\n\tnop\n1:",
  49.            neg_opcode);
  50.   else 
  51.       sprintf (buf, "cmp_br_delayed %s,%%0,%%1,%%l2\n\tnop", opcode);
  52.   return buf;
  53. }
  54.  
  55. /* Return the best assembler insn template
  56.    for moving operands[1] into operands[0] as a fullword.  */
  57.  
  58. static char *
  59. singlemove_string (operands)
  60.      rtx *operands;
  61. {
  62.   if (GET_CODE (operands[0]) == MEM)
  63.     return "st_32 %r1,%0";
  64.   if (GET_CODE (operands[1]) == MEM)
  65.     return "ld_32 %0,%1\n\tnop";
  66.   if (GET_CODE (operands[1]) == REG)
  67.     return "add_nt %0,%1,$0";
  68.   return "add_nt %0,r0,%1";
  69. }
  70.  
  71. /* Output assembler code to perform a doubleword move insn
  72.    with operands OPERANDS.  */
  73.  
  74. char *
  75. output_move_double (operands)
  76.      rtx *operands;
  77. {
  78.   enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
  79.   rtx latehalf[2];
  80.   rtx addreg0 = 0, addreg1 = 0;
  81.  
  82.   /* First classify both operands.  */
  83.  
  84.   if (REG_P (operands[0]))
  85.     optype0 = REGOP;
  86.   else if (offsetable_memref_p (operands[0]))
  87.     optype0 = OFFSOP;
  88.   else if (GET_CODE (operands[0]) == MEM)
  89.     optype0 = MEMOP;
  90.   else
  91.     optype0 = RNDOP;
  92.  
  93.   if (REG_P (operands[1]))
  94.     optype1 = REGOP;
  95.   else if (CONSTANT_P (operands[1])
  96.        || GET_CODE (operands[1]) == CONST_DOUBLE)
  97.     optype1 = CNSTOP;
  98.   else if (offsetable_memref_p (operands[1]))
  99.     optype1 = OFFSOP;
  100.   else if (GET_CODE (operands[1]) == MEM)
  101.     optype0 = MEMOP;
  102.   else
  103.     optype1 = RNDOP;
  104.  
  105.   /* Check for the cases that the operand constraints are not
  106.      supposed to allow to happen.  Abort if we get one,
  107.      because generating code for these cases is painful.  */
  108.  
  109.   if (optype0 == RNDOP || optype1 == RNDOP)
  110.     abort ();
  111.  
  112.   /* If an operand is an unoffsettable memory ref, find a register
  113.      we can increment temporarily to make it refer to the second word.  */
  114.  
  115.   if (optype0 == MEMOP)
  116.     addreg0 = find_addr_reg (operands[0]);
  117.  
  118.   if (optype1 == MEMOP)
  119.     addreg1 = find_addr_reg (operands[1]);
  120.  
  121.   /* Ok, we can do one word at a time.
  122.      Normally we do the low-numbered word first,
  123.      but if either operand is autodecrementing then we
  124.      do the high-numbered word first.
  125.  
  126.      In either case, set up in LATEHALF the operands to use
  127.      for the high-numbered word and in some cases alter the
  128.      operands in OPERANDS to be suitable for the low-numbered word.  */
  129.  
  130.   if (optype0 == REGOP)
  131.     latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
  132.   else if (optype0 == OFFSOP)
  133.     latehalf[0] = adj_offsetable_operand (operands[0], 4);
  134.   else
  135.     latehalf[0] = operands[0];
  136.  
  137.   if (optype1 == REGOP)
  138.     latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
  139.   else if (optype1 == OFFSOP)
  140.     latehalf[1] = adj_offsetable_operand (operands[1], 4);
  141.   else if (optype1 == CNSTOP)
  142.     {
  143.       if (CONSTANT_P (operands[1]))
  144.     latehalf[1] = const0_rtx;
  145.       else if (GET_CODE (operands[1]) == CONST_DOUBLE)
  146.     {
  147.       latehalf[1] = gen_rtx (CONST_INT, VOIDmode, XINT (operands[1], 1));
  148.       operands[1] = gen_rtx (CONST_INT, VOIDmode, XINT (operands[1], 0));
  149.     }
  150.     }
  151.   else
  152.     latehalf[1] = operands[1];
  153.  
  154.   /* If the first move would clobber the source of the second one,
  155.      do them in the other order.  This happens only for registers;
  156.      such overlap can't happen in memory unless the user explicitly
  157.      sets it up, and that is an undefined circumstance.  */
  158.  
  159.   if (optype0 == REGOP && optype1 == REGOP
  160.       && REGNO (operands[0]) == REGNO (latehalf[1]))
  161.     {
  162.       /* Make any unoffsetable addresses point at high-numbered word.  */
  163.       if (addreg0)
  164.     output_asm_insn ("add_nt %0,%0,$4", &addreg0);
  165.       if (addreg1)
  166.     output_asm_insn ("add_nt %0,%0,$4", &addreg1);
  167.  
  168.       /* Do that word.  */
  169.       output_asm_insn (singlemove_string (latehalf), latehalf);
  170.  
  171.       /* Undo the adds we just did.  */
  172.       if (addreg0)
  173.     output_asm_insn ("add_nt %0,%0,$-4", &addreg0);
  174.       if (addreg1)
  175.     output_asm_insn ("add_nt %0,%0,$-4", &addreg0);
  176.  
  177.       /* Do low-numbered word.  */
  178.       return singlemove_string (operands);
  179.     }
  180.  
  181.   /* Normal case: do the two words, low-numbered first.  */
  182.  
  183.   output_asm_insn (singlemove_string (operands), operands);
  184.  
  185.   /* Make any unoffsetable addresses point at high-numbered word.  */
  186.   if (addreg0)
  187.     output_asm_insn ("add_nt %0,%0,$4", &addreg0);
  188.   if (addreg1)
  189.     output_asm_insn ("add_nt %0,%0,$4", &addreg1);
  190.  
  191.   /* Do that word.  */
  192.   output_asm_insn (singlemove_string (latehalf), latehalf);
  193.  
  194.   /* Undo the adds we just did.  */
  195.   if (addreg0)
  196.     output_asm_insn ("add_nt %0,%0,$-4", &addreg0);
  197.   if (addreg1)
  198.     output_asm_insn ("add_nt %0,%0,$-4", &addreg1);
  199.  
  200.   return "";
  201. }
  202.  
  203. static char *
  204. output_fp_move_double (operands)
  205.      rtx *operands;
  206. {
  207.   if (FP_REG_P (operands[0]))
  208.     {
  209.       if (FP_REG_P (operands[1]))
  210.     return "fmov %0,%1";
  211.       if (GET_CODE (operands[1]) == REG)
  212.     {
  213.       rtx xoperands[2];
  214.       int offset = - get_frame_size () - 8;
  215.       xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
  216.       xoperands[0] = gen_rtx (CONST_INT, VOIDmode, offset + 4);
  217.       output_asm_insn ("st_32 %1,r25,%0", xoperands);
  218.       xoperands[1] = operands[1];
  219.       xoperands[0] = gen_rtx (CONST_INT, VOIDmode, offset);
  220.       output_asm_insn ("st_32 %1,r25,%0", xoperands);
  221.       xoperands[1] = operands[0];
  222.       output_asm_insn ("ld_dbl %1,r25,%0\n\tnop", xoperands);
  223.       return "";
  224.     }
  225.       return "ld_dbl %0,%1\n\tnop";
  226.     }
  227.   else if (FP_REG_P (operands[1]))
  228.     {
  229.       if (GET_CODE (operands[0]) == REG)
  230.     {
  231.       rtx xoperands[2];
  232.       int offset = - get_frame_size () - 8;
  233.       xoperands[0] = gen_rtx (CONST_INT, VOIDmode, offset);
  234.       xoperands[1] = operands[1];
  235.       output_asm_insn ("st_dbl %1,r25,%0", xoperands);
  236.       xoperands[1] = operands[0];
  237.       output_asm_insn ("ld_32 %1,r25,%0\n\tnop", xoperands);
  238.       xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
  239.       xoperands[0] = gen_rtx (CONST_INT, VOIDmode, offset + 4);
  240.       output_asm_insn ("ld_32 %1,r25,%0\n\tnop", xoperands);
  241.       return "";
  242.     }
  243.       return "st_dbl %1,%0";
  244.     }
  245. }
  246.  
  247. /* Return a REG that occurs in ADDR with coefficient 1.
  248.    ADDR can be effectively incremented by incrementing REG.  */
  249.  
  250. static rtx
  251. find_addr_reg (addr)
  252.      rtx addr;
  253. {
  254.   while (GET_CODE (addr) == PLUS)
  255.     {
  256.       if (GET_CODE (XEXP (addr, 0)) == REG)
  257.     addr = XEXP (addr, 0);
  258.       if (GET_CODE (XEXP (addr, 1)) == REG)
  259.     addr = XEXP (addr, 1);
  260.       if (CONSTANT_P (XEXP (addr, 0)))
  261.     addr = XEXP (addr, 1);
  262.       if (CONSTANT_P (XEXP (addr, 1)))
  263.     addr = XEXP (addr, 0);
  264.     }
  265.   if (GET_CODE (addr) == REG)
  266.     return addr;
  267.   return 0;
  268. }
  269.  
  270. /* Generate code to add a large integer constant to register, reg, storing
  271.  * the result in a register, target.  Offset must be 27-bit signed quantity */
  272.  
  273. static char *
  274. output_add_large_offset (target, reg, offset)
  275.      rtx target, reg;
  276.      int offset;
  277. {
  278.     rtx operands[3];
  279.     int high, n, i;
  280.     operands[0] = target, operands[1] = reg;
  281.     
  282.     for (high = offset, n = 0; 
  283.      (unsigned) (high + 0x2000) >= 0x4000; 
  284.      high >>= 1, n += 1);
  285.     operands[2] = gen_rtx (CONST_INT, VOIDmode, high);
  286.     output_asm_insn ("add_nt r2,r0,%2", operands);
  287.     i = n;
  288.     while (i >= 3)
  289.     output_asm_insn ("sll r2,r2,$3", operands), i -= 3;
  290.     if (i == 2) 
  291.     output_asm_insn ("sll r2,r2,$2", operands);
  292.     else if (i == 1)
  293.     output_asm_insn ("sll r2,r2,$1", operands);
  294.     output_asm_insn ("add_nt %0,r2,%1", operands);
  295.     if (offset - (high << n) != 0) {
  296.     operands[2] = gen_rtx (CONST_INT, VOIDmode, offset - (high << n));
  297.     output_asm_insn ("add_nt %0,%0,%2", operands);
  298.     }
  299.     return "";
  300. }
  301.  
  302. /* Additional TESTFN for matching. Like immediate_operand, but matches big
  303.  * constants */
  304.  
  305. int
  306. big_immediate_operand (op, mode)
  307.      rtx op;
  308.      enum machine_mode mode;
  309. {
  310.   return (GET_CODE (op) == CONST_INT);
  311. }
  312.  
  313.